﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ProgNetComponents.Design.Attributes
{

    public abstract class DynamicTypeDependentAttribute : Attribute, IDynamicAttribute
    {
        #region Members
        private string _PropertyName;
        private Type[] _MachingTypes;
        #endregion

        #region Properties
        public string PropertyName
        {
            get { return _PropertyName; }
        }
        public Type[] MachingTypes
        {
            get { return _MachingTypes; }
        }
        #endregion

        protected DynamicTypeDependentAttribute(string PropertyName, params Type[] types)
        {
            this._MachingTypes = types;
            this._PropertyName = PropertyName;
        }
        protected abstract Attribute GetAttribute(bool TypesMatch);

        #region IDynamicArrtibute Members

        public virtual Attribute GetRealAttribute(object target)
        {
            bool typesMatch = false;
            if (MachingTypes != null && MachingTypes.Length > 0)
            {
                PropertyInfo _PropertyInfo = target.GetType().GetSingleProperty(PropertyName);
                FieldInfo _FieldInfo = null;
                if (_PropertyInfo == null)
                    _FieldInfo = target.GetType().GetSingleField(PropertyName);

                object propertyValue = null;
                if (_PropertyInfo != null)
                    propertyValue = _PropertyInfo.GetValue(target);
                else if (_FieldInfo != null)
                    propertyValue = _FieldInfo.GetValue(target);
                else
                    throw new Exception("There is no property or field named " + PropertyName + " in type " + target.GetType().FullName);

                if (propertyValue != null)
                {
                    Type propertyType = propertyValue.GetType();
                    foreach (Type t in MachingTypes)
                    {
                        if (t.IsAssignableFrom(propertyType))
                        {
                            typesMatch = true;
                            break;
                        }
                    }
                }
            }
            return GetAttribute(typesMatch);
        }

        #endregion
    }
}
